/**
 * Copyright (c) 2013 onionframework.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.onionframework.code.support;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.HibernateException;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.DynamicParameterizedType;
import org.onionframework.code.CodeTools;
import org.onionframework.code.model.Code;
import org.onionframework.core.Onion;

/**
 * @author allan
 *
 */
public class HibernateCodeType implements CompositeUserType,DynamicParameterizedType {

	public static final String TYPE_PARAM_NAME = "type";
	public static final String TYPE_CONVERTER_NAME = "typeConverter";
	
	private Properties properties;
	
	private String role;
	
	@Override
	public void setParameterValues(Properties properties) {
		this.properties = properties;
		this.role = ((XProperty)this.properties.get(DynamicParameterizedType.XPROPERTY)).getName();
	}



	@Override
	public Object assemble(Serializable cached, SessionImplementor arg1,
			Object arg2) throws HibernateException {
		return cached;
	}



	@Override
	public Object deepCopy(Object value) throws HibernateException {
		return value;
	}



	@Override
	public Serializable disassemble(Object value, SessionImplementor arg1)
			throws HibernateException {
		return (Serializable)value;
	}



	@Override
	public boolean equals(Object x, Object y) throws HibernateException {
		if(x == y)
			return true;
		else if(x == null || y == null)
			return false;
		else
			return x.equals(y);
	}



	@Override
	public String[] getPropertyNames() {
		return new String[]{"value"};
	}

	@Override
	public Type[] getPropertyTypes() {
		return new Type[] { StandardBasicTypes.STRING};
	}

	@Override
	public Object getPropertyValue(Object value, int index)
			throws HibernateException {
		if(value == null)
			return null;
		return ((Code)value).getValue();
	}



	@Override
	public int hashCode(Object x) throws HibernateException {
		return x.hashCode();
	}

	@Override
	public boolean isMutable() {
		return false;
	}

	@Override
	public Object nullSafeGet(ResultSet rs, String[] names,
			SessionImplementor session, Object owner) throws HibernateException,
			SQLException {
		String value = rs.getString(names[0]);
		if(StringUtils.isBlank(value))
			return null;
		else{
			return Onion.getBean(CodeTools.class).getCode(owner, this.role, value);
		}
	}
	
	@Override
	public void nullSafeSet(PreparedStatement ps, Object value, int index,
			SessionImplementor arg3) throws HibernateException, SQLException {
		if(value == null)
			ps.setNull(index, Types.VARCHAR);
		else{
			ps.setString(index, ((Code)value).getValue());
		}
	}

	@Override
	public Object replace(Object original, Object target, SessionImplementor arg2,
			Object arg3) throws HibernateException {
		return original;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Class returnedClass() {
		return Code.class;
	}

	@Override
	public void setPropertyValue(Object object, int index, Object value)
			throws HibernateException {
		((Code)object).setValue((String)value);;
	}

}

